from .base import RandGen,get_real,Gener


class MatrixGener(Gener):
    retry_time = 4

    def __init__(self, w, h, gener, unique=0, ordered=0, split=' ', endl='\n'):
        '''
        unique: decides whether the value is unique,0 is default,1 means in each line, 2 means in the whole matrix
        ordered: decides wheter the value is sorted,only used when h=1,0 is default,1 means increase, 2 means decrease
        '''
        self.inited = False
        self.args = {
            'w': w,
            'h': h,
            'unique': unique,
            'ordered': ordered and h == 1
        }
        self.w = None
        self.h = None
        if isinstance(gener, RandGen):
            self.rdgen = gener
        else:
            self.rdgen = RandGen(*gener)
        self.unique = None
        self.ordered = None
        self.split = split
        self.endl = endl
        self.dat = []

    def gen(self):
        if not self.inited:
            self.inited = True
            self.w = get_real(self.args['w'])
            self.h = get_real(self.args['h'])
            self.unique = get_real(self.args['unique'])
            self.ordered = get_real(self.args['ordered'])
        self.dat = []
        self.exits = set()
        for _ in range(self.h):
            if self.unique == 1:
                self.exits.clear()
            line = []
            for __ in range(self.w):
                v = self.rdgen.read()
                cnt = 1
                while self.unique and cnt <= MatrixGener.retry_time and v in self.exits:
                    v = self.rdgen.read()
                    cnt += 1
                if cnt > MatrixGener.retry_time:
                    raise Exception('Retry', cnt, 'times with no new value')
                line.append(str(v))
                if self.ordered:
                    line.sort(reverse=(self.ordered == 2))
                self.exits.add(v)
            self.dat.append(line)

    def write(self, file):
        self.gen()
        for l in self.dat:
            file.write(self.split.join(l))
            file.write(self.endl)

    def clear(self):
        self.inited = False

    def __str__(self):
        raise Exception('call str of a matrix')


class ArrayWriter(Gener):
    def __init__(self, *args, arr=None, repeat=1, split=' ', endl='\n'):
        self.split = split
        self.endl = endl
        self.args = {
            'repeat': repeat,
            'arr': arr or args
        }
        self.inited = False

    def write(self, file):
        if not self.inited:
            self.inited = True
            self.repeat = get_real(self.args['repeat'])
            self.arr = [str(get_real(x)) for x in self.args['arr']]
        for _ in range(self.repeat):
            file.write(self.split.join(self.arr)+self.endl)

    def clear(self):
        self.inited = False
